home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / firefox-3.5.5 / components / WebContentConverter.js < prev   
Text File  |  2009-11-09  |  34KB  |  990 lines

  1. //@line 39 "/build/buildd/firefox-3.5-3.5.5+nobinonly/build-tree/mozilla/browser/components/feeds/src/WebContentConverter.js"
  2.  
  3. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  4.  
  5. const Cc = Components.classes;
  6. const Ci = Components.interfaces;
  7. const Cr = Components.results;
  8.  
  9. function LOG(str) {
  10.   dump("*** " + str + "\n");
  11. }
  12.  
  13. const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
  14. const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
  15. const WCCR_CLASSNAME = "Web Content Handler Registrar";
  16.  
  17. const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
  18. const WCC_CLASSNAME = "Web Service Handler";
  19.  
  20. const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
  21. const TYPE_ANY = "*/*";
  22.  
  23. const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto.";
  24. const PREF_CONTENTHANDLERS_BRANCH = "browser.contentHandlers.types.";
  25. const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
  26. const PREF_SELECTED_ACTION = "browser.feeds.handler";
  27. const PREF_SELECTED_READER = "browser.feeds.handler.default";
  28. const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external";
  29. const PREF_ALLOW_DIFFERENT_HOST = "gecko.handlerService.allowRegisterFromDifferentHost";
  30.  
  31. const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
  32.  
  33. const NS_ERROR_MODULE_DOM = 2152923136;
  34. const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
  35.  
  36. function WebContentConverter() {
  37. }
  38. WebContentConverter.prototype = {
  39.   convert: function WCC_convert() { },
  40.   asyncConvertData: function WCC_asyncConvertData() { },
  41.   onDataAvailable: function WCC_onDataAvailable() { },
  42.   onStopRequest: function WCC_onStopRequest() { },
  43.   
  44.   onStartRequest: function WCC_onStartRequest(request, context) {
  45.     var wccr = 
  46.         Cc[WCCR_CONTRACTID].
  47.         getService(Ci.nsIWebContentConverterService);
  48.     wccr.loadPreferredHandler(request);
  49.   },
  50.   
  51.   QueryInterface: function WCC_QueryInterface(iid) {
  52.     if (iid.equals(Ci.nsIStreamConverter) ||
  53.         iid.equals(Ci.nsIStreamListener) ||
  54.         iid.equals(Ci.nsISupports))
  55.       return this;
  56.     throw Cr.NS_ERROR_NO_INTERFACE;
  57.   }
  58. };
  59.  
  60. var WebContentConverterFactory = {
  61.   createInstance: function WCCF_createInstance(outer, iid) {
  62.     if (outer != null)
  63.       throw Cr.NS_ERROR_NO_AGGREGATION;
  64.     return new WebContentConverter().QueryInterface(iid);
  65.   },
  66.     
  67.   QueryInterface: function WCC_QueryInterface(iid) {
  68.     if (iid.equals(Ci.nsIFactory) ||
  69.         iid.equals(Ci.nsISupports))
  70.       return this;
  71.     throw Cr.NS_ERROR_NO_INTERFACE;
  72.   }
  73. };
  74.  
  75. function ServiceInfo(contentType, uri, name) {
  76.   this._contentType = contentType;
  77.   this._uri = uri;
  78.   this._name = name;
  79. }
  80. ServiceInfo.prototype = {
  81.   /**
  82.    * See nsIHandlerApp
  83.    */
  84.   get name() {
  85.     return this._name;
  86.   },
  87.   
  88.   /**
  89.    * See nsIHandlerApp
  90.    */
  91.   equals: function SI_equals(aHandlerApp) {
  92.     if (!aHandlerApp)
  93.       throw Cr.NS_ERROR_NULL_POINTER;
  94.  
  95.     if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo &&
  96.         aHandlerApp.contentType == this.contentType &&
  97.         aHandlerApp.uri == this.uri)
  98.       return true;
  99.  
  100.     return false;
  101.   },
  102.  
  103.   /**
  104.    * See nsIWebContentHandlerInfo
  105.    */
  106.   get contentType() {
  107.     return this._contentType;
  108.   },
  109.  
  110.   /**
  111.    * See nsIWebContentHandlerInfo
  112.    */
  113.   get uri() {
  114.     return this._uri;
  115.   },
  116.  
  117.   /**
  118.    * See nsIWebContentHandlerInfo
  119.    */
  120.   getHandlerURI: function SI_getHandlerURI(uri) {
  121.     return this._uri.replace(/%s/gi, encodeURIComponent(uri));
  122.   },
  123.   
  124.   QueryInterface: function SI_QueryInterface(iid) {
  125.     if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
  126.         iid.equals(Ci.nsISupports))
  127.       return this;
  128.     throw Cr.NS_ERROR_NO_INTERFACE;
  129.   }
  130. };
  131.  
  132. function WebContentConverterRegistrar() {
  133.   this._contentTypes = { };
  134.   this._autoHandleContentTypes = { };
  135. }
  136.  
  137. WebContentConverterRegistrar.prototype = {
  138.   get stringBundle() {
  139.     var sb = Cc["@mozilla.org/intl/stringbundle;1"].
  140.               getService(Ci.nsIStringBundleService).
  141.               createBundle(STRING_BUNDLE_URI);
  142.     delete WebContentConverterRegistrar.prototype.stringBundle;
  143.     return WebContentConverterRegistrar.prototype.stringBundle = sb;
  144.   },
  145.  
  146.   _getFormattedString: function WCCR__getFormattedString(key, params) {
  147.     return this.stringBundle.formatStringFromName(key, params, params.length);
  148.   },
  149.   
  150.   _getString: function WCCR_getString(key) {
  151.     return this.stringBundle.GetStringFromName(key);
  152.   },
  153.  
  154.   /**
  155.    * See nsIWebContentConverterService
  156.    */
  157.   getAutoHandler: 
  158.   function WCCR_getAutoHandler(contentType) {
  159.     contentType = this._resolveContentType(contentType);
  160.     if (contentType in this._autoHandleContentTypes)
  161.       return this._autoHandleContentTypes[contentType];
  162.     return null;
  163.   },
  164.   
  165.   /**
  166.    * See nsIWebContentConverterService
  167.    */
  168.   setAutoHandler:
  169.   function WCCR_setAutoHandler(contentType, handler) {
  170.     if (handler && !this._typeIsRegistered(contentType, handler.uri))
  171.       throw Cr.NS_ERROR_NOT_AVAILABLE;
  172.       
  173.     contentType = this._resolveContentType(contentType);
  174.     this._setAutoHandler(contentType, handler);
  175.     
  176.     var ps = 
  177.         Cc["@mozilla.org/preferences-service;1"].
  178.         getService(Ci.nsIPrefService);
  179.     var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
  180.     if (handler)
  181.       autoBranch.setCharPref(contentType, handler.uri);
  182.     else if (autoBranch.prefHasUserValue(contentType))
  183.       autoBranch.clearUserPref(contentType);
  184.      
  185.     ps.savePrefFile(null);
  186.   },
  187.   
  188.   /**
  189.    * Update the internal data structure (not persistent)
  190.    */
  191.   _setAutoHandler:
  192.   function WCCR__setAutoHandler(contentType, handler) {
  193.     if (handler) 
  194.       this._autoHandleContentTypes[contentType] = handler;
  195.     else if (contentType in this._autoHandleContentTypes)
  196.       delete this._autoHandleContentTypes[contentType];
  197.   },
  198.   
  199.   /**
  200.    * See nsIWebContentConverterService
  201.    */
  202.   getWebContentHandlerByURI:
  203.   function WCCR_getWebContentHandlerByURI(contentType, uri) {
  204.     var handlers = this.getContentHandlers(contentType, { });
  205.     for (var i = 0; i < handlers.length; ++i) {
  206.       if (handlers[i].uri == uri) 
  207.         return handlers[i];
  208.     }
  209.     return null;
  210.   },
  211.   
  212.   /**
  213.    * See nsIWebContentConverterService
  214.    */
  215.   loadPreferredHandler: 
  216.   function WCCR_loadPreferredHandler(request) {
  217.     var channel = request.QueryInterface(Ci.nsIChannel);
  218.     var contentType = this._resolveContentType(channel.contentType);
  219.     var handler = this.getAutoHandler(contentType);
  220.     if (handler) {
  221.       request.cancel(Cr.NS_ERROR_FAILURE);
  222.       
  223.       var webNavigation = 
  224.           channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
  225.       webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec), 
  226.                             Ci.nsIWebNavigation.LOAD_FLAGS_NONE, 
  227.                             null, null, null);
  228.     }      
  229.   },
  230.   
  231.   /**
  232.    * See nsIWebContentConverterService
  233.    */
  234.   removeProtocolHandler: 
  235.   function WCCR_removeProtocolHandler(aProtocol, aURITemplate) {
  236.     var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  237.               getService(Ci.nsIExternalProtocolService);
  238.     var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
  239.     var handlers =  handlerInfo.possibleApplicationHandlers;
  240.     for (let i = 0; i < handlers.length; i++) {
  241.       try { // We only want to test web handlers
  242.         let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
  243.         if (handler.uriTemplate == aURITemplate) {
  244.           handlers.removeElementAt(i);
  245.           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
  246.                    getService(Ci.nsIHandlerService);
  247.           hs.store(handlerInfo);
  248.           return;
  249.         }
  250.       } catch (e) { /* it wasn't a web handler */ }
  251.     }
  252.   },
  253.   
  254.   /**
  255.    * See nsIWebContentConverterService
  256.    */
  257.   removeContentHandler: 
  258.   function WCCR_removeContentHandler(contentType, uri) {
  259.     function notURI(serviceInfo) {
  260.       return serviceInfo.uri != uri;
  261.     }
  262.   
  263.     if (contentType in this._contentTypes) {
  264.       this._contentTypes[contentType] = 
  265.         this._contentTypes[contentType].filter(notURI);
  266.     }
  267.   },
  268.   
  269.   /**
  270.    *
  271.    */
  272.   _mappings: { 
  273.     "application/rss+xml": TYPE_MAYBE_FEED,
  274.     "application/atom+xml": TYPE_MAYBE_FEED,
  275.   },
  276.   
  277.   /**
  278.    * These are types for which there is a separate content converter aside 
  279.    * from our built in generic one. We should not automatically register
  280.    * a factory for creating a converter for these types.
  281.    */
  282.   _blockedTypes: {
  283.     "application/vnd.mozilla.maybe.feed": true,
  284.   },
  285.   
  286.   /**
  287.    * Determines the "internal" content type based on the _mappings.
  288.    * @param   contentType
  289.    * @returns The resolved contentType value. 
  290.    */
  291.   _resolveContentType: 
  292.   function WCCR__resolveContentType(contentType) {
  293.     if (contentType in this._mappings)
  294.       return this._mappings[contentType];
  295.     return contentType;
  296.   },
  297.  
  298.   _makeURI: function(aURL, aOriginCharset, aBaseURI) {
  299.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  300.                               .getService(Components.interfaces.nsIIOService);
  301.     return ioService.newURI(aURL, aOriginCharset, aBaseURI);
  302.   },
  303.  
  304.   _checkAndGetURI:
  305.   function WCCR_checkAndGetURI(aURIString, aContentWindow)
  306.   {
  307.     try {
  308.       var uri = this._makeURI(aURIString);
  309.     } catch (ex) {
  310.       // not supposed to throw according to spec
  311.       return; 
  312.     }
  313.  
  314.     // For security reasons we reject non-http(s) urls (see bug 354316),
  315.     // we may need to revise this once we support more content types
  316.     // XXX this should be a "security exception" according to spec, but that
  317.     // isn't defined yet.
  318.     if (uri.scheme != "http" && uri.scheme != "https")
  319.       throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
  320.  
  321.     // We also reject handlers registered from a different host (see bug 402287)
  322.     // The pref allows us to test the feature
  323.     var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  324.     if ((!pb.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST) ||
  325.          !pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST)) &&
  326.         aContentWindow.location.hostname != uri.host)
  327.       throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
  328.  
  329.     // If the uri doesn't contain '%s', it won't be a good handler
  330.     if (uri.spec.indexOf("%s") < 0)
  331.       throw NS_ERROR_DOM_SYNTAX_ERR; 
  332.  
  333.     return uri;
  334.   },
  335.  
  336.   /**
  337.    * Determines if a web handler is already registered.
  338.    *
  339.    * @param aProtocol
  340.    *        The scheme of the web handler we are checking for.
  341.    * @param aURITemplate
  342.    *        The URI template that the handler uses to handle the protocol.
  343.    * @return true if it is already registered, false otherwise.
  344.    */
  345.   _protocolHandlerRegistered:
  346.   function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) {
  347.     var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  348.               getService(Ci.nsIExternalProtocolService);
  349.     var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
  350.     var handlers =  handlerInfo.possibleApplicationHandlers;
  351.     for (let i = 0; i < handlers.length; i++) {
  352.       try { // We only want to test web handlers
  353.         let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
  354.         if (handler.uriTemplate == aURITemplate)
  355.           return true;
  356.       } catch (e) { /* it wasn't a web handler */ }
  357.     }
  358.     return false;
  359.   },
  360.  
  361.   /**
  362.    * See nsIWebContentHandlerRegistrar
  363.    */
  364.   registerProtocolHandler: 
  365.   function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
  366.     LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
  367.     
  368.     // First, check to make sure this isn't already handled internally (we don't
  369.     // want to let them take over, say "chrome").
  370.     var ios = Cc["@mozilla.org/network/io-service;1"].
  371.               getService(Ci.nsIIOService);
  372.     var handler = ios.getProtocolHandler(aProtocol);
  373.     if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
  374.       // This is handled internally, so we don't want them to register
  375.       // XXX this should be a "security exception" according to spec, but that
  376.       // isn't defined yet.
  377.       throw("Permission denied to add " + aURIString + "as a protocol handler");
  378.     }
  379.  
  380.     // check if it is in the black list
  381.     var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  382.     var allowed;
  383.     try {
  384.       allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
  385.     }
  386.     catch (e) {
  387.       allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
  388.     }
  389.     if (!allowed) {
  390.       // XXX this should be a "security exception" according to spec
  391.       throw("Not allowed to register a protocol handler for " + aProtocol);
  392.     }
  393.  
  394.     var uri = this._checkAndGetURI(aURIString, aContentWindow);
  395.  
  396.     var buttons, message;
  397.     if (this._protocolHandlerRegistered(aProtocol, uri.spec))
  398.       message = this._getFormattedString("protocolHandlerRegistered",
  399.                                          [aTitle, aProtocol]);
  400.     else {
  401.       // Now Ask the user and provide the proper callback
  402.       message = this._getFormattedString("addProtocolHandler",
  403.                                          [aTitle, uri.host, aProtocol]);
  404.       var fis = Cc["@mozilla.org/browser/favicon-service;1"].
  405.                 getService(Ci.nsIFaviconService);
  406.       var notificationIcon = fis.getFaviconLinkForIcon(uri);
  407.       var notificationValue = "Protocol Registration: " + aProtocol;
  408.       var addButton = {
  409.         label: this._getString("addProtocolHandlerAddButton"),
  410.         accessKey: this._getString("addHandlerAddButtonAccesskey"),
  411.         protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
  412.  
  413.         callback:
  414.         function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
  415.           var protocol = aButtonInfo.protocolInfo.protocol;
  416.           var uri      = aButtonInfo.protocolInfo.uri;
  417.           var name     = aButtonInfo.protocolInfo.name;
  418.  
  419.           var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
  420.                         createInstance(Ci.nsIWebHandlerApp);
  421.           handler.name = name;
  422.           handler.uriTemplate = uri;
  423.  
  424.           var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  425.                     getService(Ci.nsIExternalProtocolService);
  426.           var handlerInfo = eps.getProtocolHandlerInfo(protocol);
  427.           handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
  428.  
  429.           // Since the user has agreed to add a new handler, chances are good
  430.           // that the next time they see a handler of this type, they're going
  431.           // to want to use it.  Reset the handlerInfo to ask before the next
  432.           // use.
  433.           handlerInfo.alwaysAskBeforeHandling = true;
  434.  
  435.           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
  436.                    getService(Ci.nsIHandlerService);
  437.           hs.store(handlerInfo);
  438.         }
  439.       };
  440.       buttons = [addButton];
  441.     }
  442.  
  443.     var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
  444.     var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
  445.     var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
  446.     notificationBox.appendNotification(message,
  447.                                        notificationValue,
  448.                                        notificationIcon,
  449.                                        notificationBox.PRIORITY_INFO_LOW,
  450.                                        buttons);
  451.   },
  452.  
  453.   /**
  454.    * See nsIWebContentHandlerRegistrar
  455.    * If a DOM window is provided, then the request came from content, so we
  456.    * prompt the user to confirm the registration.
  457.    */
  458.   registerContentHandler: 
  459.   function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aContentWindow) {
  460.     LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
  461.  
  462.     // We only support feed types at present.
  463.     // XXX this should be a "security exception" according to spec, but that
  464.     // isn't defined yet.
  465.     var contentType = this._resolveContentType(aContentType);
  466.     if (contentType != TYPE_MAYBE_FEED)
  467.       return;
  468.  
  469.     if (aContentWindow) {
  470.       var uri = this._checkAndGetURI(aURIString, aContentWindow);
  471.   
  472.       var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
  473.       var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
  474.       var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
  475.       this._appendFeedReaderNotification(uri, aTitle, notificationBox);
  476.     }
  477.     else
  478.       this._registerContentHandler(contentType, aURIString, aTitle);
  479.   },
  480.  
  481.   /**
  482.    * Returns the browser chrome window in which the content window is in
  483.    */
  484.   _getBrowserWindowForContentWindow:
  485.   function WCCR__getBrowserWindowForContentWindow(aContentWindow) {
  486.     return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  487.                          .getInterface(Ci.nsIWebNavigation)
  488.                          .QueryInterface(Ci.nsIDocShellTreeItem)
  489.                          .rootTreeItem
  490.                          .QueryInterface(Ci.nsIInterfaceRequestor)
  491.                          .getInterface(Ci.nsIDOMWindow)
  492.                          .wrappedJSObject;
  493.   },
  494.  
  495.   /**
  496.    * Returns the <xul:browser> element associated with the given content
  497.    * window.
  498.    *
  499.    * @param aBrowserWindow
  500.    *        The browser window in which the content window is in.
  501.    * @param aContentWindow
  502.    *        The content window. It's possible to pass a child content window
  503.    *        (i.e. the content window of a frame/iframe).
  504.    */
  505.   _getBrowserForContentWindow:
  506.   function WCCR__getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
  507.     // This depends on pseudo APIs of browser.js and tabbrowser.xml
  508.     aContentWindow = aContentWindow.top;
  509.     var browsers = aBrowserWindow.getBrowser().browsers;
  510.     for (var i = 0; i < browsers.length; ++i) {
  511.       if (browsers[i].contentWindow == aContentWindow)
  512.         return browsers[i];
  513.     }
  514.   },
  515.  
  516.   /**
  517.    * Appends a notifcation for the given feed reader details.
  518.    *
  519.    * The notification could be either a pseudo-dialog which lets
  520.    * the user to add the feed reader:
  521.    * [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader?  (Add) [x] ]
  522.    *
  523.    * or a simple message for the case where the feed reader is already registered:
  524.    * [ [icon] %feed-reader-name% is already registered as a Feed Reader             [x] ]
  525.    *
  526.    * A new notification isn't appended if the given notificationbox has a
  527.    * notification for the same feed reader.
  528.    *
  529.    * @param aURI
  530.    *        The url of the feed reader as a nsIURI object
  531.    * @param aName
  532.    *        The feed reader name as it was passed to registerContentHandler
  533.    * @param aNotificationBox
  534.    *        The notification box to which a notification might be appended
  535.    * @return true if a notification has been appended, false otherwise.
  536.    */
  537.   _appendFeedReaderNotification:
  538.   function WCCR__appendFeedReaderNotification(aURI, aName, aNotificationBox) {
  539.     var uriSpec = aURI.spec;
  540.     var notificationValue = "feed reader notification: " + uriSpec;
  541.     var notificationIcon = aURI.prePath + "/favicon.ico";
  542.  
  543.     // Don't append a new notification if the notificationbox
  544.     // has a notification for the given feed reader already
  545.     if (aNotificationBox.getNotificationWithValue(notificationValue))
  546.       return false;
  547.  
  548.     var buttons, message;
  549.     if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
  550.       message = this._getFormattedString("handlerRegistered", [aName]);
  551.     else {
  552.       message = this._getFormattedString("addHandler", [aName, aURI.host]);
  553.       var self = this;
  554.       var addButton = {
  555.         _outer: self,
  556.         label: self._getString("addHandlerAddButton"),
  557.         accessKey: self._getString("addHandlerAddButtonAccesskey"),
  558.         feedReaderInfo: { uri: uriSpec, name: aName },
  559.  
  560.         /* static */
  561.         callback:
  562.         function WCCR__addFeedReaderButtonCallback(aNotification, aButtonInfo) {
  563.           var uri = aButtonInfo.feedReaderInfo.uri;
  564.           var name = aButtonInfo.feedReaderInfo.name;
  565.           var outer = aButtonInfo._outer;
  566.  
  567.           // The reader could have been added from another window mean while
  568.           if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri))
  569.             outer._registerContentHandler(TYPE_MAYBE_FEED, uri, name);
  570.  
  571.           // avoid reference cycles
  572.           aButtonInfo._outer = null;
  573.  
  574.           return false;
  575.         }
  576.       };
  577.       buttons = [addButton];
  578.     }
  579.  
  580.     aNotificationBox.appendNotification(message,
  581.                                         notificationValue,
  582.                                         notificationIcon,
  583.                                         aNotificationBox.PRIORITY_INFO_LOW,
  584.                                         buttons);
  585.     return true;
  586.   },
  587.  
  588.   /**
  589.    * Save Web Content Handler metadata to persistent preferences. 
  590.    * @param   contentType
  591.    *          The content Type being handled
  592.    * @param   uri
  593.    *          The uri of the web service
  594.    * @param   title
  595.    *          The human readable name of the web service
  596.    *
  597.    * This data is stored under:
  598.    * 
  599.    *    browser.contentHandlers.type0 = content/type
  600.    *    browser.contentHandlers.uri0 = http://www.foo.com/q=%s
  601.    *    browser.contentHandlers.title0 = Foo 2.0alphr
  602.    */
  603.   _saveContentHandlerToPrefs: 
  604.   function WCCR__saveContentHandlerToPrefs(contentType, uri, title) {
  605.     var ps = 
  606.         Cc["@mozilla.org/preferences-service;1"].
  607.         getService(Ci.nsIPrefService);
  608.     var i = 0;
  609.     var typeBranch = null;
  610.     while (true) {
  611.       typeBranch = 
  612.         ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
  613.       try {
  614.         typeBranch.getCharPref("type");
  615.         ++i;
  616.       }
  617.       catch (e) {
  618.         // No more handlers
  619.         break;
  620.       }
  621.     }
  622.     if (typeBranch) {
  623.       typeBranch.setCharPref("type", contentType);
  624.       var pls = 
  625.           Cc["@mozilla.org/pref-localizedstring;1"].
  626.           createInstance(Ci.nsIPrefLocalizedString);
  627.       pls.data = uri;
  628.       typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
  629.       pls.data = title;
  630.       typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
  631.     
  632.       ps.savePrefFile(null);
  633.     }
  634.   },
  635.   
  636.   /**
  637.    * Determines if there is a type with a particular uri registered for the 
  638.    * specified content type already.
  639.    * @param   contentType
  640.    *          The content type that the uri handles
  641.    * @param   uri
  642.    *          The uri of the 
  643.    */
  644.   _typeIsRegistered: function WCCR__typeIsRegistered(contentType, uri) {
  645.     if (!(contentType in this._contentTypes))
  646.       return false;
  647.       
  648.     var services = this._contentTypes[contentType];
  649.     for (var i = 0; i < services.length; ++i) {
  650.       // This uri has already been registered
  651.       if (services[i].uri == uri)
  652.         return true;
  653.     }
  654.     return false;
  655.   },
  656.   
  657.   /**
  658.    * Gets a stream converter contract id for the specified content type.
  659.    * @param   contentType
  660.    *          The source content type for the conversion.
  661.    * @returns A contract id to construct a converter to convert between the 
  662.    *          contentType and *\/*.
  663.    */
  664.   _getConverterContractID: function WCCR__getConverterContractID(contentType) {
  665.     const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
  666.     return template.replace(/%s/, contentType);
  667.   },
  668.   
  669.   /**
  670.    * Register a web service handler for a content type.
  671.    * 
  672.    * @param   contentType
  673.    *          the content type being handled
  674.    * @param   uri
  675.    *          the URI of the web service
  676.    * @param   title
  677.    *          the human readable name of the web service
  678.    */
  679.   _registerContentHandler:
  680.   function WCCR__registerContentHandler(contentType, uri, title) {
  681.     this._updateContentTypeHandlerMap(contentType, uri, title);
  682.     this._saveContentHandlerToPrefs(contentType, uri, title);
  683.  
  684.     if (contentType == TYPE_MAYBE_FEED) {
  685.       // Make the new handler the last-selected reader in the preview page
  686.       // and make sure the preview page is shown the next time a feed is visited
  687.       var pb = Cc["@mozilla.org/preferences-service;1"].
  688.                getService(Ci.nsIPrefService).getBranch(null);
  689.       pb.setCharPref(PREF_SELECTED_READER, "web");
  690.   
  691.       var supportsString = 
  692.         Cc["@mozilla.org/supports-string;1"].
  693.         createInstance(Ci.nsISupportsString);
  694.         supportsString.data = uri;
  695.       pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString,
  696.                          supportsString);
  697.       pb.setCharPref(PREF_SELECTED_ACTION, "ask");
  698.       this._setAutoHandler(TYPE_MAYBE_FEED, null);
  699.     }
  700.   },
  701.  
  702.   /**
  703.    * Update the content type -> handler map. This mapping is not persisted, use
  704.    * registerContentHandler or _saveContentHandlerToPrefs for that purpose.
  705.    * @param   contentType
  706.    *          The content Type being handled
  707.    * @param   uri
  708.    *          The uri of the web service
  709.    * @param   title
  710.    *          The human readable name of the web service
  711.    */
  712.   _updateContentTypeHandlerMap: 
  713.   function WCCR__updateContentTypeHandlerMap(contentType, uri, title) {
  714.     if (!(contentType in this._contentTypes))
  715.       this._contentTypes[contentType] = [];
  716.  
  717.     // Avoid adding duplicates
  718.     if (this._typeIsRegistered(contentType, uri)) 
  719.       return;
  720.     
  721.     this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
  722.     
  723.     if (!(contentType in this._blockedTypes)) {
  724.       var converterContractID = this._getConverterContractID(contentType);
  725.       var cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
  726.       cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID, 
  727.                          WebContentConverterFactory);
  728.     }
  729.   },
  730.   
  731.   /**
  732.    * See nsIWebContentConverterService
  733.    */
  734.   getContentHandlers: 
  735.   function WCCR_getContentHandlers(contentType, countRef) {
  736.     countRef.value = 0;
  737.     if (!(contentType in this._contentTypes))
  738.       return [];
  739.     
  740.     var handlers = this._contentTypes[contentType];
  741.     countRef.value = handlers.length;
  742.     return handlers;
  743.   },
  744.   
  745.   /**
  746.    * See nsIWebContentConverterService
  747.    */
  748.   resetHandlersForType: 
  749.   function WCCR_resetHandlersForType(contentType) {
  750.     // currently unused within the tree, so only useful for extensions; previous
  751.     // impl. was buggy (and even infinite-looped!), so I argue that this is a
  752.     // definite improvement
  753.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  754.   },
  755.   
  756.   /**
  757.    * Registers a handler from the settings on a preferences branch.
  758.    *
  759.    * @param branch
  760.    *        an nsIPrefBranch containing "type", "uri", and "title" preferences
  761.    *        corresponding to the content handler to be registered
  762.    */
  763.   _registerContentHandlerWithBranch: function(branch) {
  764.     /**
  765.      * Since we support up to six predefined readers, we need to handle gaps 
  766.      * better, since the first branch with user-added values will be .6
  767.      * 
  768.      * How we deal with that is to check to see if there's no prefs in the 
  769.      * branch and stop cycling once that's true.  This doesn't fix the case
  770.      * where a user manually removes a reader, but that's not supported yet!
  771.      */
  772.     var vals = branch.getChildList("", {});
  773.     if (vals.length == 0)
  774.       return;
  775.  
  776.     try {
  777.       var type = branch.getCharPref("type");
  778.       var uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
  779.       var title = branch.getComplexValue("title",
  780.                                          Ci.nsIPrefLocalizedString).data;
  781.       this._updateContentTypeHandlerMap(type, uri, title);
  782.     }
  783.     catch(ex) {
  784.       // do nothing, the next branch might have values
  785.     }
  786.   },
  787.  
  788.   /**
  789.    * Load the auto handler, content handler and protocol tables from 
  790.    * preferences.
  791.    */
  792.   _init: function WCCR__init() {
  793.     var ps = 
  794.         Cc["@mozilla.org/preferences-service;1"].
  795.         getService(Ci.nsIPrefService);
  796.  
  797.     var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
  798.                  .getChildList("", {});
  799.  
  800.     // first get the numbers of the providers by getting all ###.uri prefs
  801.     var nums = [];
  802.     for (var i = 0; i < kids.length; i++) {
  803.       var match = /^(\d+)\.uri$/.exec(kids[i]);
  804.       if (!match)
  805.         continue;
  806.       else
  807.         nums.push(match[1]);
  808.     }
  809.  
  810.     // sort them, to get them back in order
  811.     nums.sort(function(a, b) {return a - b;});
  812.  
  813.     // now register them
  814.     for (var i = 0; i < nums.length; i++) {
  815.       var branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + nums[i] + ".");
  816.       this._registerContentHandlerWithBranch(branch);
  817.     }
  818.  
  819.     // We need to do this _after_ registering all of the available handlers, 
  820.     // so that getWebContentHandlerByURI can return successfully.
  821.     try {
  822.       var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
  823.       var childPrefs = autoBranch.getChildList("", { });
  824.       for (var i = 0; i < childPrefs.length; ++i) {
  825.         var type = childPrefs[i];
  826.         var uri = autoBranch.getCharPref(type);
  827.         if (uri) {
  828.           var handler = this.getWebContentHandlerByURI(type, uri);
  829.           this._setAutoHandler(type, handler);
  830.         }
  831.       }
  832.     }
  833.     catch (e) {
  834.       // No auto branch yet, that's fine
  835.       //LOG("WCCR.init: There is no auto branch, benign");
  836.     }
  837.   },
  838.  
  839.   /**
  840.    * See nsIObserver
  841.    */
  842.   observe: function WCCR_observe(subject, topic, data) {
  843.     var os = 
  844.         Cc["@mozilla.org/observer-service;1"].
  845.         getService(Ci.nsIObserverService);
  846.     switch (topic) {
  847.     case "app-startup":
  848.       os.addObserver(this, "browser-ui-startup-complete", false);
  849.       break;
  850.     case "browser-ui-startup-complete":
  851.       os.removeObserver(this, "browser-ui-startup-complete");
  852.       this._init();
  853.       break;
  854.     }
  855.   },
  856.   
  857.   /**
  858.    * See nsIFactory
  859.    */
  860.   createInstance: function WCCR_createInstance(outer, iid) {
  861.     if (outer != null)
  862.       throw Cr.NS_ERROR_NO_AGGREGATION;
  863.     return this.QueryInterface(iid);
  864.   },
  865.  
  866.   /**
  867.    * See nsIClassInfo
  868.    */
  869.   getInterfaces: function WCCR_getInterfaces(countRef) {
  870.     var interfaces = 
  871.         [Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
  872.          Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
  873.     countRef.value = interfaces.length;
  874.     return interfaces;
  875.   },
  876.   getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
  877.     return null;
  878.   },
  879.   contractID: WCCR_CONTRACTID,
  880.   classDescription: WCCR_CLASSNAME,
  881.   classID: WCCR_CLASSID,
  882.   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
  883.   flags: Ci.nsIClassInfo.DOM_OBJECT,
  884.   
  885.   /**
  886.    * See nsISupports
  887.    */
  888.   QueryInterface: XPCOMUtils.generateQI(
  889.      [Ci.nsIWebContentConverterService, 
  890.       Ci.nsIWebContentHandlerRegistrar,
  891.       Ci.nsIObserver,
  892.       Ci.nsIClassInfo,
  893.       Ci.nsIFactory,
  894.       Ci.nsISupports]),
  895.  
  896.   _xpcom_categories: [{
  897.     category: "app-startup",
  898.     service: true
  899.   }]
  900. };
  901.  
  902. function NSGetModule(cm, file) {
  903.   return XPCOMUtils.generateModule([WebContentConverterRegistrar]);
  904. }
  905.  
  906. //@line 44 "/build/buildd/firefox-3.5-3.5.5+nobinonly/build-tree/mozilla/toolkit/content/debug.js"
  907.  
  908. var EXPORTED_SYMBOLS = ["NS_ASSERT"];
  909.  
  910. var gTraceOnAssert = true;
  911.  
  912. /**
  913.  * This function provides a simple assertion function for JavaScript.
  914.  * If the condition is true, this function will do nothing.  If the
  915.  * condition is false, then the message will be printed to the console
  916.  * and an alert will appear showing a stack trace, so that the (alpha
  917.  * or nightly) user can file a bug containing it.  For future enhancements, 
  918.  * see bugs 330077 and 330078.
  919.  *
  920.  * To suppress the dialogs, you can run with the environment variable
  921.  * XUL_ASSERT_PROMPT set to 0 (if unset, this defaults to 1).
  922.  *
  923.  * @param condition represents the condition that we're asserting to be
  924.  *                  true when we call this function--should be
  925.  *                  something that can be evaluated as a boolean.
  926.  * @param message   a string to be displayed upon failure of the assertion
  927.  */
  928.  
  929. function NS_ASSERT(condition, message) {
  930.   if (condition)
  931.     return;
  932.  
  933.   var releaseBuild = true;
  934.   var defB = Components.classes["@mozilla.org/preferences-service;1"]
  935.                        .getService(Components.interfaces.nsIPrefService)
  936.                        .getDefaultBranch(null);
  937.   try {
  938.     switch (defB.getCharPref("app.update.channel")) {
  939.       case "nightly":
  940.       case "beta":
  941.       case "default":
  942.         releaseBuild = false;
  943.     }
  944.   } catch(ex) {}
  945.  
  946.   var caller = arguments.callee.caller;
  947.   var assertionText = "ASSERT: " + message + "\n";
  948.  
  949.   if (releaseBuild) {
  950.     // Just report the error to the console
  951.     Components.utils.reportError(assertionText);
  952.     return;
  953.   }
  954.  
  955.   // Otherwise, dump to stdout and launch an assertion failure dialog
  956.   dump(assertionText);
  957.  
  958.   var stackText = "";
  959.   if (gTraceOnAssert) {
  960.     stackText = "Stack Trace: \n";
  961.     var count = 0;
  962.     while (caller) {
  963.       stackText += count++ + ":" + caller.name + "(";
  964.       for (var i = 0; i < caller.arguments.length; ++i) {
  965.         var arg = caller.arguments[i];
  966.         stackText += arg;
  967.         if (i < caller.arguments.length - 1)
  968.           stackText += ",";
  969.       }
  970.       stackText += ")\n";
  971.       caller = caller.arguments.callee.caller;
  972.     }
  973.   }
  974.  
  975.   var environment = Components.classes["@mozilla.org/process/environment;1"].
  976.                     getService(Components.interfaces.nsIEnvironment);
  977.   if (environment.exists("XUL_ASSERT_PROMPT") &&
  978.       !parseInt(environment.get("XUL_ASSERT_PROMPT")))
  979.     return;
  980.  
  981.   var source = null;
  982.   if (this.window)
  983.     source = this.window;
  984.   var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
  985.            getService(Components.interfaces.nsIPromptService);
  986.   ps.alert(source, "Assertion Failed", assertionText + stackText);
  987. }
  988. //@line 944 "/build/buildd/firefox-3.5-3.5.5+nobinonly/build-tree/mozilla/browser/components/feeds/src/WebContentConverter.js"
  989.  
  990.